import re
import sys
import os
import hashlib
import zlib

import about
from md5Hash import Ui_MainWindow
from PyQt5.QtWidgets import QApplication, QMainWindow, QFileDialog, QMessageBox


def format_time(atime):
    """
    时间格式化函数
    :param atime:
    :return:
    """
    import time
    return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(atime))


def format_file_size(size):
    """
    格式化文件大小函数
    :param size:
    :return:
    """
    for count in ['Bytes', 'KB', 'MB', 'GB']:
        if -1024.0 < size < 1024.0:
            return "%3.1f%s" % (size, count)
        size /= 1024.0
    return "%3.1f%s" % (size, 'TB')


"""
st_mode	    保护模式
st_ino	    索引号
st_nlink	硬链接号（被连接数目）
st_dev	    设备名
st_uid	    用户 ID	
st_gid	    组 ID
st_size	    文件大小，以字节为单位	
st_mtime	文件最后一次修改时间
st_atime	最后一次访问时间	
st_ctime	最后一次状态变化的时间，操作系统不会，该属性对应的结果也不同，例如在 Windows 操作系统下返回的就是文件的创建时间。

# print("索引号：", file_info.st_ino)
# print("被连接数目：", file_info.st_nlink)
# print("文件大小:", format_file_size(file_info.st_size))
# print("最后一次访问时间:", format_time(file_info.st_atime))
# print("最后一次修改时间:", format_time(file_info.st_mtime))
# print("最后一次状态变化的时间：", format_time(file_info.st_ctime))
"""


# 小文件的处理函数
def get_md5_small(file_path):
    md5 = None
    if os.path.exists(file_path) and os.path.isfile(file_path):
        with open(file_path, 'rb') as f:
            md5_obj = hashlib.md5()
            md5_obj.update(f.read())
            hash_code = md5_obj.hexdigest()
            md5 = str(hash_code).lower()
    return md5


# 大文件的处理函数
def get_md5_big(file_path):
    md5 = None
    if os.path.exists(file_path) and os.path.isfile(file_path):
        with open(file_path, 'rb') as f:
            md5_obj = hashlib.md5()
            while True:
                d = f.read(8096)
                if not d:
                    break
                md5_obj.update(d)
            hash_code = md5_obj.hexdigest()
            md5 = str(hash_code).lower()
    return md5


# 小文件的处理函数
def get_cipher_small(file_path, fun):
    md5 = None
    if os.path.exists(file_path) and os.path.isfile(file_path):
        with open(file_path, 'rb') as f:
            if fun == 'md5':
                md5_obj = hashlib.md5()
            elif fun == 'sha1':
                md5_obj = hashlib.sha1()
            elif fun == 'sha256':
                md5_obj = hashlib.sha256()
            elif fun == 'sha512':
                md5_obj = hashlib.sha512()
            elif fun == 'crc32':
                md5 = hex(crc32(file_path)).upper()
                return md5
            md5_obj.update(f.read())
            hash_code = md5_obj.hexdigest()
            md5 = str(hash_code).lower().upper()
    return md5


# 大文件的处理函数
def get_cipher_big(file_path, fun):
    md5 = None
    if os.path.exists(file_path) and os.path.isfile(file_path):
        with open(file_path, 'rb') as f:
            if fun == 'md5':
                md5_obj = hashlib.md5()
            elif fun == 'sha1':
                md5_obj = hashlib.sha1()
            elif fun == 'sha256':
                md5_obj = hashlib.sha256()
            elif fun == 'sha512':
                md5_obj = hashlib.sha512()
            elif fun == 'crc32':
                md5 = hex(crc32(file_path))
                return md5
            while True:
                d = f.read(8096)
                if not d:
                    break
                md5_obj.update(d)
            hash_code = md5_obj.hexdigest()
            md5 = str(hash_code).lower().upper()
    return md5


def get_md5(file, fuc):
    """
    根据文件大小计算文件MD5值
    :param fuc:算法
    :param file:文件
    :return:加密值
    """
    path = file
    if os.path.exists(path=path) and os.path.isfile(path=path):
        # 200M以上的当作大文件
        if os.path.getsize(path) >= 200 * 1024 * 1024:
            md5 = get_cipher_big(path, fuc)
        else:
            md5 = get_cipher_small(path, fuc)
        return md5


def crc32(filepath):
    block_size = 1024 * 1024
    num = 0
    try:
        fd = open(filepath, 'rb')
        while True:
            buffer = fd.read(block_size)
            if len(buffer) == 0:  # EOF or file empty. return hashes
                fd.close()
                if sys.version_info[0] < 3 and num < 0:
                    num += 2 ** 32
                return num  # 返回的是十进制的值
            num = zlib.crc32(buffer, num)
    except Exception as e:
        if sys.version_info[0] < 3:
            error = e
        else:
            error = str(e)
        return 0, error


# 定义全局变量存放选择的文件
files = []
chooses = []


class MainForm(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super(MainForm, self).__init__()
        self.setupUi(self)
        self.open.triggered.connect(self.run)  # 信号和槽函数，打开文件
        self.actionfds.triggered.connect(self.info)  # 关于
        self.md5.stateChanged.connect(self.choose)
        self.sha1.stateChanged.connect(self.choose)
        self.sha256.stateChanged.connect(self.choose)
        self.sha512.stateChanged.connect(self.choose)
        self.crc32.stateChanged.connect(self.choose)
        self.pushButton.clicked.connect(self.count)
        self.pushButton_2.clicked.connect(self.clean)
        self.pushButton_3.clicked.connect(self.reset)

        self.setAcceptDrops(True)
        self.textEdit.textChanged.connect(self.move_file)  # 检测输入框文本变化

    def choose(self):
        global chooses
        chooses = []
        chooses.append('md5') if self.md5.isChecked() else ''
        chooses.append('sha1') if self.sha1.isChecked() else ''
        chooses.append('sha256') if self.sha256.isChecked() else ''
        chooses.append('sha512') if self.sha512.isChecked() else ''
        chooses.append('crc32') if self.crc32.isChecked() else ''

    def count(self):
        if len(files):
            for q in range(len(files)):
                file_name = files[q]
                self.textEdit.append("<font color=\"#C34908\">文件名称: %s</font> " % file_name)
                if len(chooses):
                    for i in range(len(chooses)):
                        fun = chooses[i]
                        has = get_md5(file_name, fun)
                        self.textEdit.append("<font color=\"#0000FF\">%s: %s</font> " % (fun, has))
                    self.textEdit.append('\n')
                else:
                    self.textEdit.append("<font color=\"#FF0000\">请选择加密方式...</font> ")

    def clean(self):
        self.textEdit.clear()

    # 定义触发函数
    def open_file(self):
        global files
        file_name, file_type = QFileDialog.getOpenFileNames(self, "选取文件", os.getcwd(),
                                                            "All Files(*);;Text Files(*.txt)")
        print(file_name)
        files = file_name
        return files

    # 定义触发函数
    def show_info(self, file):
        for i in range(len(file)):
            file_info = os.stat(file[i])
            file_size = format_file_size(file_info.st_size)
            a_time = format_time(file_info.st_atime)
            m_time = format_time(file_info.st_mtime)
            c_time = format_time(file_info.st_ctime)
            self.textEdit.append('文件名称:' + file[i])
            self.textEdit.append('文件大小:' + file_size)
            self.textEdit.append('最后一次修改时间:' + m_time)
            self.textEdit.append('最后一次访问时间:' + a_time)
            self.textEdit.append('最后一次状态变化的时间:' + c_time)
            self.textEdit.append('\n')

    def info(self):
        text = about.about
        QMessageBox.about(self, "关于本软件", text)

    def reset(self):
        global files
        files = []
        self.textEdit.clear()

    def move_file(self):
        """
        实现文件拖动添加文件
        :return:
        """
        global files
        if 0 == self.textEdit.toPlainText().find('file:///'):
            text = self.textEdit.toPlainText()
            if re.match('^file:///', text):
                file = self.textEdit.toPlainText().replace('file:///', '')
                self.textEdit.clear()
                files.append(file)
            print(files)

    def run(self):
        file = self.open_file()
        self.show_info(file)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = MainForm()
    # 调用信号和槽的函数以及空间管理等函数
    win.show()
    sys.exit(app.exec_())
